package algoGenetic;

import java.util.*;

/**
 * Cette classe implémente le problème du mot mystère. Chaque instance de
 * MotGenetique représente une solution possible au problème, c'est-à-dire
 * un mot de même longueur que le mot mystère.
 * @author simon
 * @version 1.0
 */
public class MotGenetique implements Genome {
	
	/**
	 * Cet attribut de classe est le mot mystère qui doit être trouvé. Le mot
	 * mystère doit être composé uniquement de caractères dans l'intervalle
	 * [a-z]
	 */
	private static String mystere;
	
	/**
	 * Chiffre entre 0 et 1 représentant le taux de mutation des mots créés
	 * à chaque génération.
	 */
	private static double tauxMutation=0.1;
	
	/**
	 * Le mot de l'instance MotGenetique, dont le nombre de caractère est
	 * le même que celui de <code>mystere</code>
	 */
	private String code;
	
	/**
	 * Constructeur par défaut. Construit un mot aléatoire ayant le même nombre
	 * de caractère que <code>mystere</code>.
	 */
	public MotGenetique() {
		Random r = new Random();
		this.code="";
		for (int i=0; i<mystere.length(); i++){
			this.code += (char) (r.nextInt(26)+97);
		}
	}
	
	/**
	 * Construit une solution 
	 * @param code
	 */
	public MotGenetique(String code) {
		this.code=code;
	}
	
	/**
	 * Initialise le mot mystère aléatoirement. Le mot est compris de 3 à 10
	 * caractères dans l'intervalle [a-z]
	 */
	public static void initialisation() {
		Random r = new Random();
		mystere="";
		for (int i=-3; i<r.nextInt(7); i++) {
			mystere += (char) (r.nextInt(26)+97);
		}
	}
	
	/**
	 * Initialise le mot mystère à la chaîne de caractère passée en paramètre
	 * @param motMystere solution du problème. Ce mot doit être limité aux
	 * caractères [a-z].
	 */
	public static void initialisation(String motMystere) {
		mystere=motMystere;
	}
	
	/**
	 * Retourne le nombre de lettre en commun entre l'instance MotGenetique
	 * et le mot mystere. Une lettre n'est considérée commune que si elle est
	 * situé à la même position dans les deux mots.
	 * @return le nombre de lettre en commun entre l'instance MotGenetique
	 * et le mot mystere
	 */
	private int valeur() {
		int valeur = 0 ;
		for (int i=0; i<mystere.length(); i++) {
			if (mystere.charAt(i)==this.code.charAt(i)) {
				valeur ++;
			}
		}
		return valeur;
	}
	
	/**
	 * Renvoie vrai si l'instance correspond au mot mystère
	 * @return vrai si l'instance correspond au mot mystère
	 */
	public boolean isFit() {
		return this.valeur()==mystere.length();
	}
	
	@Override
	public int compareTo(Genome arg0) {
		MotGenetique arg1 = (MotGenetique) arg0;
		return (this.valeur()-arg1.valeur());
	}

	@Override
	public void mutation() {
		Random r = new Random();
		for (int i=0; i<code.length(); i++) {
			if (r.nextInt()<tauxMutation) {
				char newChar = (char) (r.nextInt(26)+97);
				String newCode = "";
				if (i>0) {
					newCode = code.substring(0,i);
				}
				newCode += newChar;
				if (i<code.length()) {
					newCode += code.substring(i+1,code.length());
				}
				code = newCode;
			}
		}

	}
	
	/**
	 * Retourne un mot issu du croisement entre l'objet appelant et le gène
	 * parent. Le mot retourné est crée en mélangeant les n premières lettres
	 * de l'objet appelant et les m-n dernières de parent, où m est la longueur
	 * du mot mystère. Les deux mots génétiques doivent être de même longueur
	 * que le mot mystère
	 * @param parent le gène dont est issu la deuxième moitié du mot retourné.
	 * Si cet objet n'est pas de la classe MotGenetique, l'objet retourné sera
	 * null.
	 * @return un mot issu du croisement entre l'objet appelant et le gène
	 * parent
	 */
	public Genome croisement(Genome parent) {
		if (parent.getClass() != this.getClass()){
			return null;
		}
		MotGenetique motParent=(MotGenetique)parent;
		Random r=new Random();
		String nouveauMot="";
		int separ=r.nextInt(mystere.length());
		for (int i=0; i<separ; i++) {
			nouveauMot += this.code.charAt(i);
		}
		for (int j=separ; j<mystere.length(); j++) {
			nouveauMot += motParent.code.charAt(j);
		}
		return new MotGenetique(nouveauMot);
	}

	@Override
	public String toString() {
		return "MotGenetique [code=" + code + "] valide = "+
		((float)this.valeur()*100/(float)mystere.length())+"%";
	}
	
}
